package com.nine.dao;


import com.nine.dao.dto.BaseDaoQuery;

import com.nine.dao.annotation.Column;
import com.nine.dao.dto.Page;


import com.nine.dao.sql.BaseSQLToString;
import org.apache.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;


import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 实现注入接口类，差异化实现继承此接口来实现功能（自制组件）
 *
 * @author zjb
 */

public class BaseDao {

    private static Logger log = Logger.getLogger(BaseDao.class.getClass());

    @Autowired
    BaseDaoMapper mapper;


    /**
     * 转换查询到的map信息为需要映射的类
     *
     * @param map
     * @param target
     * @param <T>
     * @return
     */
    private <T> T convertDB(Map<String, Object> map, Class<T> target) {
        T t = null;
        try {
            if (map == null) return t;
            Set<String> keys = map.keySet();
            t = BeanUtils.instantiate(target);
            //获取所有参数变量名称
            for (Field field : t.getClass().getDeclaredFields()) {
                field.setAccessible(true);
                for (String key : keys) {
                    //获取变量上的注释，实现与数据库表名称的映射
                    Column column = field.getAnnotation(Column.class);
                    if (column != null) {
                        if (key.equals(column.name())) {
                            field.set(t, map.get(key));
                        }
                    } else {
                        if (key.equals(field.getName())) {
                            field.set(t, map.get(key));
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new RuntimeException(e.getMessage());
        }
        return t;

    }

    /**
     * 集合方式转换查询到的map信息，返回集合
     *
     * @param src
     * @param target
     * @param <T>
     * @return
     */
    private <T> List<T> convertListDB(List<Map<String, Object>> src, Class<T> target) {
        if (src == null) {
            return null;
        }
        List<T> targetList = new ArrayList<>();
        for (Map<String, Object> obj : src) {
            targetList.add(convertDB(obj, target));
        }
        return targetList;
    }

    /**
     * 转换实体类属性值为键值对形式
     * 以@column注释属性为主，实现实体类属性和库表属性映射
     * 没设@column的话就已属性名称为映射
     * 时间类型要进行格式转换
     *
     * @return
     */
    private List<Map<String, Object>> convertToKeyValue(Object target) throws IllegalAccessException {
        List<Map<String, Object>> baseKeyValueDtos = new ArrayList<>();
        Field[] fields = target.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            if (field.get(target) != null) {
                Map<String, Object> keyValueDto = new HashMap<>();
                //获取变量上的注释，实现与数据库表名称的映射
                Column column = field.getAnnotation(Column.class);
                if (column != null) {
                    keyValueDto.put("title", column.name());
                } else {
                    keyValueDto.put("title", field.getName());
                }
                if (field.getType() == Date.class) {
                    //时间类型默认转换为yyyy-MM-dd HH:mm:ss格式
                    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    String time = df.format(field.get(target));
                    keyValueDto.put("value", time);
                } else {
                    keyValueDto.put("value", field.get(target));
                }
                baseKeyValueDtos.add(keyValueDto);
            }
        }
        return baseKeyValueDtos;
    }

    /**
     * 查询结果集合
     *
     * @param query
     * @param dataBaseName
     * @param result
     * @param target
     * @param <T>
     * @return
     */
    public <T> List<T> findListByEx(BaseDaoQuery query, List<String> dataBaseName, List<String> result, Class<T> target) {
        try {
            List<Map<String, Object>> findMaps = mapper.findListByExample(query, dataBaseName, result, null);
            return convertListDB(findMaps, target);
        } catch (Exception e) {
            log.error("查询失败：" + e.getMessage());
            throw new RuntimeException("查询失败：" + e.getMessage());
        }
    }

    /**
     * 分页查询结果
     *
     * @param query
     * @param dataBaseName
     * @param result
     * @param page
     * @param target
     * @param <T>
     * @return
     */
    public <T> Page<T> findPageByEx(BaseDaoQuery query, List<String> dataBaseName, List<String> result, Page page, Class<T> target) {
        try {
            List<Map<String, Object>> findMaps = mapper.findListByExample(query, dataBaseName, result, page);
            page.setData(convertListDB(findMaps, target));
            String size = findOne(query, dataBaseName, "count(*)");
            long totalSize = Long.parseLong(size);
            page.setTotalSize(totalSize);
            return page;
        } catch (Exception e) {
            log.error("查询失败：" + e.getMessage());
            throw new RuntimeException("查询失败：" + e.getMessage());
        }
    }

    /**
     * 条件查询某个具体值
     *
     * @param query
     * @param dataBaseName
     * @param result
     * @return
     */
    public String findOne(BaseDaoQuery query, List<String> dataBaseName, String result) {
        try {
            List<String> datas = mapper.findOneByExample(query, dataBaseName, Arrays.asList(result), null);
            return datas.get(0);
        } catch (Exception e) {
            log.error("查询失败：" + e.getMessage());
            throw new RuntimeException("查询失败：" + e.getMessage());
        }

    }

    /**
     * 条件查询某个具体值集合
     *
     * @param query
     * @param dataBaseName
     * @param result
     * @return
     */
    public List<String> findListOne(BaseDaoQuery query, List<String> dataBaseName, String result) {
        try {
            return mapper.findOneByExample(query, dataBaseName, Arrays.asList(result), null);
        } catch (Exception e) {
            log.error("查询失败：" + e.getMessage());
            throw new RuntimeException("查询失败：" + e.getMessage());
        }

    }

    /**
     * 查询单个结果
     * 如果查询条件为空，则返回第一条数据
     *
     * @param query
     * @param dataBaseName
     * @param result
     * @param target
     * @param <T>
     * @return
     */
    public <T> T findByEx(BaseDaoQuery query, List<String> dataBaseName, List<String> result, Class<T> target) {
        try {
            List<Map<String, Object>> findMaps = mapper.findListByExample(query, dataBaseName, result, null);
            if (!CollectionUtils.isEmpty(findMaps)) {
                return convertDB(findMaps.get(0), target);
            } else {
                return null;
            }
        } catch (Exception e) {
            log.error("查询失败：" + e.getMessage());
            throw new RuntimeException("查询失败：" + e.getMessage());
        }
    }

    /**
     * 指定条件删除库表信息
     *
     * @param dataBaseName
     * @param query
     * @return
     */
    public int deleteByEx(String dataBaseName, BaseDaoQuery query) {
        try {
            return mapper.deleteByBaseDaoExample(dataBaseName, query);
        } catch (Exception e) {
            log.error("删除失败：" + e.getMessage());
            throw new RuntimeException("删除失败：" + e.getMessage());
        }
    }

    /**
     * 保存某实体类信息到指定库表
     *
     * @param dataBaseName
     * @param target
     * @return
     */
    public int save(String dataBaseName, Object target) {
        try {
//            List<Map<String, Object>> keyValueDtos = convertToKeyValue(target);
//            if (!CollectionUtils.isEmpty(keyValueDtos)) {
//
//            }
            return mapper.insertByValues(dataBaseName, target);
        } catch (Exception e) {
            log.error("保存失败：" + e.getMessage());
            throw new RuntimeException("保存失败：" + e.getMessage());
        }
        //return 0;
    }

    /**
     * 指定条件更新库表字段
     *
     * @param dataBaseName
     * @param query
     * @param target
     * @return
     */
    public int updateByEx(String dataBaseName, BaseDaoQuery query, Object target) {
        try {
            List<Map<String, Object>> keyValueDtos = convertToKeyValue(target);
            if (!CollectionUtils.isEmpty(keyValueDtos)) {
                return mapper.updateByValues(dataBaseName, query, keyValueDtos);
            }
        } catch (Exception e) {
            log.error("更新失败：" + e.getMessage());
            throw new RuntimeException("更新失败：" + e.getMessage());
        }
        return 0;
    }


}
